<template>
  <div id="login-three-container"></div>
</template>
<script setup name="login">
import { onMounted } from "vue";
import * as THREE from "three";
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
import lodash from "lodash";

// 容器
let container;
// 场景
let scene;

// 宽度
let width;
// 高度
let height;
// 深度
let depth = 1400;
// 相机z轴上的位置
let zAxisNumber;
// 相机
let camera;
// 渲染器
let renderer;
// 球体网格
let sphere;
// 点的初始参数
let parameters;
// 材质
let materials = [];
// 星星的初始位置
let particles_init_position;
// 声明点1在z轴上的移动位置
let zprogress;
// 声明点2在z轴上的移动位置
let zprogress_second;
// 声明点1
let particles_first = [];
// 声明点2
let particles_second = [];
// 声明星云对象1
let cloud_first;
// 声明星云对象2
let cloud_second;
// 声明星云运动的渲染函数1
let renderCloud_first;
// 声明星云运动的渲染函数2
let renderCloud_second;

// 加载图片
const image_sky = new URL("../assets/images/sky.png", import.meta.url).href;
const image_earth = new URL("../assets/images/earth_bg.png", import.meta.url)
  .href;
const image_start1 = new URL("../assets/images/starflake1.png", import.meta.url)
  .href;
const image_start2 = new URL("../assets/images/starflake2.png", import.meta.url)
  .href;
const image_cloud = new URL("../assets/images/cloud.png", import.meta.url).href;
onMounted(() => {
  container = document.getElementById("login-three-container");
  width = container.clientWidth;
  height = container.clientHeight;
  initScene();
  initSceneGg();
  initCamera();
  initSphereModal();
  initlLight();
  // 定义初始位置
  particles_init_position = -zAxisNumber - depth / 2;
  zprogress = particles_init_position;
  zprogress_second = particles_init_position * 2;
  particles_first = initSceneStar(particles_init_position);
  particles_second = initSceneStar(zprogress_second);
  cloud_first = initCloud(400, 200);
  cloud_second = initCloud(200, 100);
  renderCloud_first = initCloudMove(
    cloud_first,
    [
      new THREE.Vector3(-width / 10, 0, -depth / 2),
      new THREE.Vector3(-width / 4, height / 8, 0),
      new THREE.Vector3(-width / 4, 0, zAxisNumber),
    ],
    0.0002
  );
  renderCloud_second = initCloudMove(
    cloud_second,
    [
      new THREE.Vector3(width / 8, height / 8, -depth / 2),
      new THREE.Vector3(width / 8, height / 8, zAxisNumber),
    ],
    0.0008
  );
  initRenderer();
  initOrbitControls();
  animate();
});

// 初始化场景
const initScene = () => {
  scene = new THREE.Scene();
  // 添加雾的效果
  scene.fog = new THREE.Fog(0x000000, 0, 10000);
};

// 添加背景
const initSceneGg = () => {
  new THREE.TextureLoader().load(image_sky, (texture) => {
    // 创建立方体
    const gemogetry = new THREE.BoxGeometry(width, height, depth);
    // 创建材质
    const material = new THREE.MeshBasicMaterial({
      map: texture,
      side: THREE.BackSide,
    });
    // 创建网格
    const mesh = new THREE.Mesh(gemogetry, material);
    // 添加到场景中
    scene.add(mesh);
  });
};

// 初始化相机
const initCamera = () => {
  // 视野夹角
  const fov = 15;
  // 计算相机距离物体的距离
  const distance = width / 2 / Math.tan(Math.PI / 12);
  zAxisNumber = Math.floor(distance - depth / 2);
  camera = new THREE.PerspectiveCamera(fov, width / height, 1, 30000);
  // 设置相机所在的位置
  camera.position.set(0, 0, zAxisNumber);
  // 看向原点
  camera.lookAt(0, 0, 0);
};
// 初始化球体
const initSphereModal = () => {
  const gemogetry = new THREE.SphereGeometry(50, 64, 32);
  const material = new THREE.MeshPhongMaterial();
  material.map = new THREE.TextureLoader().load(image_earth);
  // 网格
  sphere = new THREE.Mesh(gemogetry, material);
  sphere.position.set(-400, 200, -200);
  scene.add(sphere);
};
// 光照
const initlLight = () => {
  // 环境光
  const ambientLight = new THREE.AmbientLight(0xffffff, 1);
  scene.add(ambientLight);
  // 点光源
  const light = new THREE.PointLight(0x0655fd, 5, 0);
  light.position.set(0, 100, -200);
  scene.add(light);
};
// 星球的自转
const renderSphereRotate = () => {
  sphere.rotateY(0.001);
};
// 初始化场景星星的效率
const initSceneStar = (initZPosition) => {
  const gemogetry = new THREE.BufferGeometry();
  // 星星位置的坐标
  const vertices = [];
  // 创建纹理
  const textureLoader = new THREE.TextureLoader();
  const spritel = textureLoader.load(image_start1);
  const sprite2 = textureLoader.load(image_start2);
  // 星星的数据
  const pointsGeometry = [];
  // 声明点的参数
  parameters = [
    [[0.6, 100, 0.75], spritel, 50],
    [[0, 0, 1], sprite2, 20],
  ];
  // 创建1500个星星
  for (let i = 0; i < 1500; i++) {
    const x = THREE.MathUtils.randFloatSpread(width);
    const y = lodash.random(0, height / 2);
    const z = lodash.random(-depth / 2, zAxisNumber);
    vertices.push(x, y, z);
  }

  gemogetry.setAttribute(
    "position",
    new THREE.Float32BufferAttribute(vertices, 3)
  );
  // 创建2中不同的材质
  for (let i = 0; i < parameters.length; i++) {
    // 颜色
    const color = parameters[i][0];
    //  纹理
    const sprite = parameters[i][1];
    // 点的大小
    const size = parameters[i][2];
    materials[i] = new THREE.PointsMaterial({
      size,
      map: sprite,
      blending: THREE.AdditiveBlending, // 图片变形问题
      transparent: true, // 图片背景透明
      depthTest: true,
    });
    // 设置颜色HSL
    materials[i].color.setHSL(color[0], color[1], color[2]);
    // 创建物体
    const particles = new THREE.Points(gemogetry, materials[i]);
    particles.rotation.x = Math.random() * 0.2 - 0.15;
    particles.rotation.y = Math.random() * 0.2 - 0.15;
    particles.rotation.z = Math.random() * 0.2 - 0.15;
    particles.position.setZ(initZPosition);
    pointsGeometry.push(particles);
    scene.add(particles);
  }

  return pointsGeometry;
};
// 渲染星星的运动
const renderStarMove = () => {
  // 星星颜色交替变化
  const time = Date.now() * 0.00005;
  for (let i = 0; i < parameters.length; i++) {
    const color = parameters[i][0];
    const h = ((360 * (color[0] + time)) % 360) / 360;
    materials[i].color.setHSL(color[0], color[1], parseFloat(h.toFixed(2)));
  }
  // 星星的运动
  zprogress += 1;
  zprogress_second += 1;
  if (zprogress >= zAxisNumber + depth / 2) {
    zprogress = particles_init_position;
  } else {
    particles_first.forEach((item) => {
      item.position.setZ(zprogress);
    });
  }

  if (zprogress_second >= zAxisNumber + depth / 2) {
    zprogress_second = particles_init_position;
  } else {
    particles_second.forEach((item) => {
      item.position.setZ(zprogress_second);
    });
  }
};
// 渲染星云的效果
const initCloud = (width, height) => {
  const gemogetry = new THREE.PlaneGeometry(width, height);
  const textureLoader = new THREE.TextureLoader();
  const cloudTexture = textureLoader.load(image_cloud);
  const cloudMaterial = new THREE.MeshBasicMaterial({
    map: cloudTexture,
    blending: THREE.AdditiveBlending,
    transparent: true,
    depthTest: false,
  });
  const cloud = new THREE.Mesh(gemogetry, cloudMaterial);
  scene.add(cloud);
  return cloud;
};
// 创建星云的运动函数
const initCloudMove = (cloud, route, speed) => {
  let cloudProgress = 0;
  // 创建三维曲线
  const curve = new THREE.CatmullRomCurve3(route);
  return () => {
    if (cloudProgress <= 1) {
      cloudProgress += speed;
      // 当前位置
      const point = curve.getPoint(cloudProgress);
      if (point && point.x) {
        cloud.position.set(point.x, point.y, point.z);
      }
    } else {
      cloudProgress = 0;
    }
  };
};
// 渲染器
const initRenderer = () => {
  renderer = new THREE.WebGLRenderer();
  // 定义渲染器的尺寸
  renderer.setSize(width, height);
  container.appendChild(renderer.domElement);
};

// 添加轨道控制
const initOrbitControls = () => {
  const controls = new OrbitControls(camera, renderer.domElement);
  controls.enabled = true;
  controls.update();
};

//  动画刷新
const animate = () => {
  requestAnimationFrame(animate);
  renderSphereRotate();
  renderStarMove();
  renderCloud_first();
  renderCloud_second();
  renderer.render(scene, camera);
};
</script>
<script>
export default {
  name: "loginPage",
};
</script>
<style scoped lang="less">
#login-three-container {
  width: 100vw;
  height: 100vh;
  overflow: hidden;
}
</style>
